package square;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;

import java.math.BigDecimal;

import org.junit.Before;
import org.junit.Test;

import border.Door;
import border.Wall;


public class NormalSquareTest {
	
	private static NormalSquare square150Temp59humid;
	private static NormalSquare square100Temp50humidSlipperyFloor;


	@Before
	public void setUp() throws Exception {
		square150Temp59humid = new NormalSquare(new Temperature(150),new BigDecimal("59.01"));
		square100Temp50humidSlipperyFloor = new NormalSquare(new Temperature(100),new BigDecimal("50"),true);
	}

	@Test
	public void constructor_FullConstructor(){
		Square square = new NormalSquare(new Temperature(100),new BigDecimal("20.02"),true);
		assertEquals(100,square.getTemperature().convertTo(TemperatureScale.CELCIUS).getTemperatureValue(),0.001);
		assertEquals(new BigDecimal("20.02"),square.getHumidity());
		assertTrue(square.getBorder(Direction.FLOOR) != null);
		assertTrue(square.getBorder(Direction.EAST) == null);
		assertTrue(((Wall) square.getBorder(Direction.FLOOR)).isSlippery());
	}
	
	@Test
	public void constructor_temperatureAndHumidity(){
		Square square = new NormalSquare(new Temperature(100),new BigDecimal("20.02"));
		assertEquals(100,square.getTemperature().convertTo(TemperatureScale.CELCIUS).getTemperatureValue(),0.001);
		assertEquals(new BigDecimal("20.02"),square.getHumidity());
		assertTrue(square.getBorder(Direction.FLOOR) != null);
		assertTrue(square.getBorder(Direction.EAST) == null);
		assertFalse(((Wall) square.getBorder(Direction.FLOOR)).isSlippery());
	}
	
	@Test
	public void constructor_DefaultConstructor(){
		Square square = new NormalSquare();
		assertEquals(new NormalSquare().getMinTemperature(), square.getTemperature());
		assertEquals(new BigDecimal(0), square.getHumidity());
		assertTrue(square.getBorder(Direction.FLOOR) != null);
	}
	
	@Test
	public void setTemperature_TrueCase() {
		square150Temp59humid.setTemperature(new Temperature(3000, TemperatureScale.CELCIUS));
		assertEquals ( 3000, square150Temp59humid.getTemperature().convertTo(TemperatureScale.CELCIUS).getTemperatureValue(), 0.001);
	}
	
	@Test(expected = Exception.class)
	public void setTemperature_IllegalCase() {
		square150Temp59humid.setTemperature(null);
	}
	
	@Test
	public void isValidTemperature_ToHigh(){
		assertFalse(square150Temp59humid.isValidTemperature(new Temperature(new NormalSquare().getMaxTemperature().getTemperatureValue()+1, new NormalSquare().getMaxTemperature().getTemperatureScale())));
	}
	
	@Test
	public void isValidTemperature_ToLow(){
		assertFalse(square150Temp59humid.isValidTemperature(new Temperature(new NormalSquare().getMinTemperature().getTemperatureValue()-1,new NormalSquare().getMinTemperature().getTemperatureScale())));
	}
	
	@Test
	public void coldDamage_TrueCase(){
		Square square = new NormalSquare(new Temperature(-50),new BigDecimal("4"));
		assertEquals(square.coldDamage(),4);
	}
	
	@Test
	public void coldDamage_NoDamage(){
		assertEquals(square150Temp59humid.coldDamage(),0);
	}
	
	@Test
	public void heatDamage_TrueCase(){
		assertEquals(square150Temp59humid.heatDamage(), 23);
	}
	
	@Test
	public void heatDamage_NoDamage(){
		Square square = new NormalSquare(new Temperature(34), new BigDecimal("4"));
		assertEquals(square.heatDamage(), 0);
	}
	
	
//	These tests are for private methods.
//  If you want to run these test you have to make the used methods public.
//	
//	@Test
//	public void setHeatDamageLowerBoundary_SingleCase(){
//		Square.setHeatDamageLowerBoundary(-500);
//		assertEquals(square150Temp59humid.getHeatDamageLowerBoundary(), -500);
//		
//	}
//	
//	@Test
//	public void setHeatDamageRate_TrueCase(){
//		Square.setHeatDamageRate(5);
//		assertEquals(square150Temp59humid.getHeatDamageRate(), 5);
//	}
	
	@Test (expected = IllegalArgumentException.class)
	public void setHeatDamageRate_NegativeRate() throws Exception{
		NormalSquare.setHeatDamageRate(-5);
	}
	
	@Test
	public void setHumidity_TrueCase(){
		square150Temp59humid.setHumidity(new BigDecimal("99.99"));
		assertEquals(square150Temp59humid.getHumidity(),new BigDecimal("99.99") );
	}
	
	@Test 
	public void isValidHumidity_ToLow(){
		assertFalse(NormalSquare.isValidHumidity(new BigDecimal("-1")));
	}
	
	@Test 
	public void isValidHumidity_ToHigh(){
		assertFalse(NormalSquare.isValidHumidity(new BigDecimal("100.5")));
	}
	
	@Test
	public void isValidHumidity_ExcessiveScale(){
		assertFalse(NormalSquare.isValidHumidity(new BigDecimal("10.555")));
	}
	
	@Test
	public void rustDamage_DamageCase(){
		assertEquals(square150Temp59humid.rustDamage(), 4);
	}
	
	@Test
	public void rustDamage_noDamage(){
		assertEquals(new NormalSquare(new Temperature(0),new BigDecimal(31)).rustDamage(),0);
		assertEquals(new NormalSquare().rustDamage(),0);
	}
	
	@Test
	public void isSlippery_SlipperyFloorMaterial(){
		assertTrue(square100Temp50humidSlipperyFloor.hasSlipperyFloorMaterial());
	}
	
	@Test
	public void isSlippery_Aquaplaning(){
		square150Temp59humid.setHumidity(new BigDecimal("100"));
		assertTrue(square150Temp59humid.isSlippery());
	}
	
	@Test
	public void isSlippery_LayerOfIce() {
		square150Temp59humid.setTemperature(new Temperature(-10,TemperatureScale.CELCIUS));
		assertTrue(square150Temp59humid.isSlippery());
	}
	
	@Test
	public void isSlippery_FalseCase(){
		assertFalse(square150Temp59humid.isSlippery());
	}
	
	@Test
	public void getInhabitability_SingleCase(){
		assertEquals(square150Temp59humid.getInhabitability(), -17.02, 0.01);
	}
	
	@Test
	public void getDirectionOfBorder_TrueCase(){
		Wall w = new Wall(square150Temp59humid,Direction.WEST, false);
		assertEquals(Direction.WEST, square150Temp59humid.getDirectionOfBorder(w));
	}
	
	@Test
	public void getDirectionOfBorder_NonEffectiveBorder(){
		assertEquals(square150Temp59humid.getDirectionOfBorder(null), null);
	}
	
	@Test
	public void getDirectionOfBorder_NotAnAttachedBorder(){
		assertEquals(square150Temp59humid.getDirectionOfBorder(new Wall(square100Temp50humidSlipperyFloor,Direction.WEST, false)), null);
	}
	
	@Test
	public void hasBorder_TrueCase(){
		Wall w = new Wall(square150Temp59humid,Direction.WEST, false);
		assertTrue(square150Temp59humid.hasBorder(w));
	}
	
	@Test
	public void hasBorder_NonEffectiveBorder(){
		assertFalse(square150Temp59humid.hasBorder(null));
	}
	
	@Test 
	public void hasBorder_NotAnAttachedBorder(){
		Wall w = new Wall(square100Temp50humidSlipperyFloor,Direction.WEST, false);
		assertFalse(square150Temp59humid.hasBorder(w));
	}
	
	@Test
	public void hasAsNeighbor_TrueCase(){
		Wall w = new Wall(square100Temp50humidSlipperyFloor,square150Temp59humid,Direction.WEST, false);
		assertTrue(square150Temp59humid.hasAsNeighbor(square100Temp50humidSlipperyFloor));
	}
	
	@Test
	public void hasAsNeighbor_NonEffectiveSquare(){
		assertFalse(square150Temp59humid.hasAsNeighbor(null));
	}
	
	@Test
	public void hasAsNeighbor_NotNeighboringSquare(){
		assertFalse(square150Temp59humid.hasAsNeighbor(square100Temp50humidSlipperyFloor));
	}
	
	@Test (expected=IllegalArgumentException.class)
	public void attachBorder_4Doors(){
		Door d1 = new Door(square150Temp59humid, Direction.NORTH, false);
		Door d2 = new Door(square150Temp59humid, Direction.EAST, false);
		Door d3 = new Door(square150Temp59humid, Direction.WEST, false);
		Door d4 = new Door(square150Temp59humid, Direction.SOUTH, false);
	}
	
	@Test
	public void hasProperBorders_SingleCase(){
		assertTrue(square150Temp59humid.hasProperBorders());
	}
	
	@Test
	public void removeBorder_TrueCaseTerminatedSquare(){
		Wall w = new Wall(square150Temp59humid,Direction.WEST, false);
		square150Temp59humid.terminate();
		assertFalse(square150Temp59humid.hasBorder(w));
	}
	
	@Test
	public void removeBorder_TrueCaseTerminatedBorder(){
		Wall w = new Wall(square150Temp59humid,Direction.WEST, false);
		w.terminate();
		assertFalse(square150Temp59humid.hasBorder(w));
	}
	
	@Test (expected = AssertionError.class)
	public void removeBorder_FalseCase(){
		Wall w = new Wall(square150Temp59humid,Direction.WEST, false);
		w.detach(square150Temp59humid);
		assertFalse(square150Temp59humid.hasBorder(w));
	}
	
	@Test
	public void removeBorder_HasOnly1Border(){
		square150Temp59humid.removeBorder(square150Temp59humid.getBorder(Direction.FLOOR));
		assertTrue(square150Temp59humid.getBorder(Direction.FLOOR) != null);
	}
	
	@Test
	public void terminate_SingleCase(){
		square150Temp59humid.terminate();
		assertTrue(square150Temp59humid.isTerminated());
		assertEquals(square150Temp59humid.getNbBorders(), 0);
	}
	
	@Test
	public void hasNoNeighbours_TrueCase(){
		assertTrue(square150Temp59humid.hasNoNeighbours());
	}
	
	@Test
	public void hasNoNeighbours_FalseCase(){
		Wall w = new Wall(square150Temp59humid,square100Temp50humidSlipperyFloor,Direction.WEST, false);
		assertFalse(square150Temp59humid.hasNoNeighbours());
	}
	

	
	
	
	
	

}
